package com.huafeng.Interceptors;

import com.alibaba.fastjson.JSON;
import com.huafeng.annotations.Log;
import com.huafeng.commonutil.IpUtils;
import com.huafeng.commonutil.JwtHelper;
import com.huafeng.model.base.Result;
import com.huafeng.model.entity.SysOperLog;
import com.huafeng.model.enums.OperationTypeEnum;
import com.huafeng.model.enums.OperatorTypeEnum;
import com.huafeng.model.enums.ResultCodeEnum;
import com.huafeng.model.exception.BusinessException;
import com.huafeng.service.SysOperLogService;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;

/**
 * @author 花风
 * @date 2023/8/18 18:19
 * @Description 操作日志拦截器
 */
@Order(2)
@Component
@Aspect
public class OperLogInterceptor {

    @Resource
    private SysOperLogService sysOperLogService;

    @AfterReturning(pointcut = "@annotation(log)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Log log, Object jsonResult){
        handlerLog(joinPoint,log,jsonResult);
    }

    @AfterThrowing(value = "@annotation(log)",throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint,Log log,Exception e){
        handlerLog(joinPoint,log,e);
    }

    private void handlerLog(JoinPoint joinPoint, Log log, Object jsonResult) {
        try {
            // 从请求上下文中获取请求信息
            RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();

            SysOperLog sysOperLog = new SysOperLog();
            sysOperLog.setStatus(1);

            // 根据request获取IP
            String ip = IpUtils.getIp(request);
            sysOperLog.setOperIp(ip);
            // 请求地址
            sysOperLog.setOperUrl(request.getRequestURI());

            // 根据token获取用户信息
            String token = request.getHeader("token");
            if (StringUtils.isEmpty(token) || StringUtils.isBlank(token)){
                throw new BusinessException(ResultCodeEnum.ILLEGAL_REQUEST);
            }
            sysOperLog.setOperName(JwtHelper.getUserName(token));

            // 获取注解上的信息并进行保存
            OperationTypeEnum operationTypeEnum = log.operationType();
            sysOperLog.setBusinessType(operationTypeEnum.name());

            OperatorTypeEnum operatorTypeEnum = log.operatorType();
            sysOperLog.setOperatorType(operatorTypeEnum.name());

            String method = request.getMethod();
            sysOperLog.setRequestMethod(method);

            if (jsonResult instanceof Exception){
                // 如果是异常
                sysOperLog.setStatus(0);
                sysOperLog.setErrorMsg(((Exception) jsonResult).getMessage());
            }

            // 获取方法信息
            String methodName = joinPoint.getSignature().getName();
            String className = joinPoint.getTarget().getClass().getSimpleName();
            sysOperLog.setMethod(className + "." + methodName + "()");

            if (log.saveRequestParams()){
                Object[] args = joinPoint.getArgs();
                if (!Objects.isNull(args)){
                    sysOperLog.setOperParam(Arrays.toString(args));
                }
            }
            sysOperLog.setTitle(log.model());

            if (log.saveResponseData() && !Objects.isNull(jsonResult)){
                Result result = JSON.parseObject(JSON.toJSONString(jsonResult), Result.class);
                result.setData(null);
                sysOperLog.setJsonResult(JSON.toJSONString(result));
            }

            sysOperLogService.save(sysOperLog);
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}
